class Circle {
  constructor ({ origin, speed, color, angle, context }) {
    this.origin = origin
    this.position = { ...this.origin }
    this.color = color
    this.speed = speed
    this.angle = angle
    this.context = context
    this.renderCount = 0
  }

  draw () {
    this.context.fillStyle = this.color
    this.context.beginPath()
    this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
    this.context.fill()
  }

  move () {
    this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
    this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
    this.renderCount++
  }
}

class Boom {
  constructor ({ origin, context, circleCount = 10, area }) {
    this.origin = origin
    this.context = context
    this.circleCount = circleCount
    this.area = area
    this.stop = false
    this.circles = []
  }

  randomArray (range) {
    const length = range.length
    const randomIndex = Math.floor(length * Math.random())
    return range[randomIndex]
  }

  randomColor () {
    const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
    return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
  }

  randomRange (start, end) {
    return (end - start) * Math.random() + start
  }

  init () {
    for (let i = 0; i < this.circleCount; i++) {
      const circle = new Circle({
        context: this.context,
        origin: this.origin,
        color: this.randomColor(),
        angle: this.randomRange(Math.PI - 1, Math.PI + 1),
        speed: this.randomRange(1, 6)
      })
      this.circles.push(circle)
    }
  }

  move () {
    this.circles.forEach((circle, index) => {
      if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
        return this.circles.splice(index, 1)
      }
      circle.move()
    })
    if (this.circles.length == 0) {
      this.stop = true
    }
  }

  draw () {
    this.circles.forEach(circle => circle.draw())
  }
}

class CursorSpecialEffects {
  constructor () {
    this.computerCanvas = document.createElement('canvas')
    this.renderCanvas = document.createElement('canvas')

    this.computerContext = this.computerCanvas.getContext('2d')
    this.renderContext = this.renderCanvas.getContext('2d')

    this.globalWidth = window.innerWidth
    this.globalHeight = window.innerHeight

    this.booms = []
    this.running = false

    this.MouseDown = this.handleMouseDown.bind(this);
    this.PageHide = this.handlePageHide.bind(this);
  }

  handleMouseDown (e) {
    const boom = new Boom({
      origin: { x: e.clientX, y: e.clientY }, context: this.computerContext, area: {
        width: this.globalWidth, height: this.globalHeight
      }
    })
    boom.init()
    this.booms.push(boom)
    this.running || this.run()
  }

  handlePageHide () {
    this.booms = []
    this.running = false
  }

  init () {
    const style = this.renderCanvas.style
    style.position = 'fixed'
    style.top = style.left = 0
    style.zIndex = '999999999999999999999999999999999999999999'
    style.pointerEvents = 'none'

    style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
    style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

    document.body.append(this.renderCanvas)
    window.addEventListener('mousedown', this.MouseDown)
    window.addEventListener('pagehide', this.PageHide)
  }

  run () {
    this.running = true
    if (this.booms.length === 0) {
      return this.running = false
    }

    requestAnimationFrame(this.run.bind(this))

    this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
    this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

    this.booms.forEach((boom, index) => {
      if (boom.stop) {
        return this.booms.splice(index, 1)
      }
      boom.move()
      boom.draw()
    })
    this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
  }

  destroy () {
    this.renderCanvas.parentElement && this.renderCanvas.parentElement.removeChild(this.renderCanvas)
    window.removeEventListener('mousedown', this.MouseDown)
    window.removeEventListener('pagehide', this.PageHide)
  }
}

class Heart {
  constructor () {
    this.stop = true
    this.hearts = [];
    window.requestAnimationFrame = (function () {
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
        setTimeout(callback, 1000 / 60)
      }
    })();
  }

  init () {
    this.stop = false
    this.css(".heart{z-index:100000000;width:50px;height:50px;position:fixed;background-image:url(https://files.cnblogs.com/files/yanggb/jump-pig.gif);background-size:50px 50px;");
    window.addEventListener("click", e => {
      this.createHeart(e)
    })
    this.gameloop()
  }

  gameloop () {
    for (var i = 0; i < this.hearts.length; i++) {
      if (this.hearts[i].alpha <= 0) {
        document.body.removeChild(this.hearts[i].el);
        this.hearts.splice(i, 1);
        continue
      }
      this.hearts[i].y--;
      this.hearts[i].scale += 0.004;
      this.hearts[i].alpha -= 0.013;
      this.hearts[i].el.style.cssText = "left:" + this.hearts[i].x + "px;top:" + this.hearts[i].y + "px;opacity:" + this.hearts[i].alpha + ";transform:scale(" + this.hearts[i].scale + "," + this.hearts[i].scale + ");"
    }
    requestAnimationFrame(this.gameloop)
  }

  createHeart (event) {
    var d = document.createElement("div");
    d.className = "heart";
    this.hearts.push({ el: d, x: event.clientX - 5, y: event.clientY - 35, scale: 1, alpha: 1 });
    document.body.appendChild(d)
  }

  css (css) {
    var style = document.createElement("style");
    style.type = "text/css";
    try {
      style.appendChild(document.createTextNode(css))
    } catch (ex) {
      style.styleSheet.cssText = css
    }
    document.getElementsByTagName("head")[0].appendChild(style)
  }

  destroy () {
    this.stop = true
  }
}

class Lzkz {
  constructor () {
    this.xg1 = new CursorSpecialEffects()
    this.xg2 = new Heart()
  }

  setLzxg (val) {
    this.xg1.destroy()
    this.xg2.destroy()
    let it = this[val]
    if (it) {
      it.init()
    }
  }
}

export default new Lzkz();
